/*
 * %W% %E%
 *
 * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.sun.corba.se.impl.oa.poa ;

import org.omg.PortableServer.Servant ;

import org.omg.PortableServer.POAPackage.WrongPolicy ;
import org.omg.PortableServer.POAPackage.ServantNotActive ;
import org.omg.PortableServer.POAPackage.ServantAlreadyActive ;
import org.omg.PortableServer.POAPackage.ObjectNotActive ;
import org.omg.PortableServer.POAPackage.ObjectAlreadyActive ;

import com.sun.corba.se.impl.orbutil.concurrent.SyncUtil ;

import com.sun.corba.se.impl.orbutil.ORBUtility ;
import com.sun.corba.se.impl.orbutil.ORBConstants ;

import com.sun.corba.se.impl.javax.rmi.CORBA.Util ;

import com.sun.corba.se.impl.oa.NullServantImpl ;

public abstract class POAPolicyMediatorBase_R extends POAPolicyMediatorBase {
    protected ActiveObjectMap activeObjectMap ;
    
    POAPolicyMediatorBase_R( Policies policies, POAImpl poa ) 
    {
	super( policies, poa ) ;

	// assert policies.retainServants() && policies.useActiveObjectMapOnly()
	if (!policies.retainServants())
	    throw poa.invocationWrapper().policyMediatorBadPolicyInFactory() ;

        activeObjectMap = ActiveObjectMap.create(poa, !isUnique);
    }
    
    public void returnServant() 
    {
	// NO-OP
    }

    public void clearAOM() 
    {
	activeObjectMap.clear() ;
	activeObjectMap = null ;
    }

    protected Servant internalKeyToServant( ActiveObjectMap.Key key )
    {
	AOMEntry entry = activeObjectMap.get(key);
	if (entry == null)
	    return null ;

	return activeObjectMap.getServant( entry ) ;
    }

    protected Servant internalIdToServant( byte[] id )
    {
	ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
	return internalKeyToServant( key ) ;
    }

    protected void activateServant( ActiveObjectMap.Key key, AOMEntry entry, Servant servant )
    {
	setDelegate(servant, key.id );

        if (orb.shutdownDebugFlag) {
            System.out.println("Activating object " + servant + 
	        " with POA " + poa);
        }

	activeObjectMap.putServant( servant, entry ) ;

        if (Util.isInstanceDefined()) {
	    POAManagerImpl pm = (POAManagerImpl)poa.the_POAManager() ;
	    POAFactory factory = pm.getFactory() ;
            factory.registerPOAForServant(poa, servant);
        }
    }

    public final void activateObject(byte[] id, Servant servant) 
	throws WrongPolicy, ServantAlreadyActive, ObjectAlreadyActive
    {
	if (isUnique && activeObjectMap.contains(servant))
	    throw new ServantAlreadyActive();
	ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
        
	AOMEntry entry = activeObjectMap.get( key ) ;

        // Check for an ObjectAlreadyActive error
	entry.activateObject() ;

	activateServant( key, entry, servant ) ;
    }
    
    public Servant deactivateObject( byte[] id ) 
	throws ObjectNotActive, WrongPolicy 
    {
	ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
	return deactivateObject( key ) ;
    }
    
    protected void deactivateHelper( ActiveObjectMap.Key key, AOMEntry entry, 
	Servant s ) throws ObjectNotActive, WrongPolicy
    {
	// Default does nothing, but the USE_SERVANT_MANAGER case
	// must handle etherealization

	activeObjectMap.remove(key);

        if (Util.isInstanceDefined()) {
	    POAManagerImpl pm = (POAManagerImpl)poa.the_POAManager() ;
	    POAFactory factory = pm.getFactory() ;
            factory.unregisterPOAForServant(poa, s);
        }
    }

    public Servant deactivateObject( ActiveObjectMap.Key key ) 
	throws ObjectNotActive, WrongPolicy 
    {
	if (orb.poaDebugFlag) {
	    ORBUtility.dprint( this, 
		"Calling deactivateObject for key " + key ) ;
	}

	try {
	    AOMEntry entry = activeObjectMap.get(key);
	    if (entry == null)
		throw new ObjectNotActive();

	    Servant s = activeObjectMap.getServant( entry ) ;
	    if (s == null)
		throw new ObjectNotActive();

	    if (orb.poaDebugFlag) {
		System.out.println("Deactivating object " + s + " with POA " + poa);
	    }

	    deactivateHelper( key, entry, s ) ;

	    return s ;
	} finally {
	    if (orb.poaDebugFlag) {
		ORBUtility.dprint( this, 
		    "Exiting deactivateObject" ) ;
	    }
	}
    }

    public byte[] servantToId( Servant servant ) throws ServantNotActive, WrongPolicy
    {	
	// XXX needs to handle call from an invocation on this POA

	if (!isUnique && !isImplicit)
	    throw new WrongPolicy();

	if (isUnique) {
	    ActiveObjectMap.Key key = activeObjectMap.getKey(servant);
	    if (key != null)
		return key.id ;
	} 

	// assert !isUnique || (servant not in activateObjectMap)
	
	if (isImplicit)
	    try {
		byte[] id = newSystemId() ;
		activateObject( id, servant ) ;
		return id ; 
	    } catch (ObjectAlreadyActive oaa) {
		// This can't occur here, since id is always brand new.
		throw poa.invocationWrapper().servantToIdOaa( oaa ) ;
	    } catch (ServantAlreadyActive s) {
		throw poa.invocationWrapper().servantToIdSaa( s ) ;
	    } catch (WrongPolicy w) {
		throw poa.invocationWrapper().servantToIdWp( w ) ;
	    }

	throw new ServantNotActive();
    }
}

